#include "font.h"
// Include freetype
#include <ft2build.h>
#include <freetype/freetype.h>
#include <freetype/ftglyph.h>
#include <freetype/ftoutln.h>
#include <freetype/fttrigon.h>

#include <iostream>
using namespace std;

int next_p2(int x) {
	int size = 1;
	while (size < x) {
		size = size << 1;
	}
	return size;
}


Font::Font(const char *fname, int size ) : size(size) {
	
	FT_Library library;
	FT_Face face;
	
	// open freetype
	if (FT_Init_FreeType(&library)) {
		cerr << "Could not init font renderer" << endl;
		exit(0);
	}
	
	// load the font
	if (FT_New_Face(library, fname, 0, &face)) {
		cerr << "Font file is not ttf" << endl;
		exit(0);
	}
	
	FT_Set_Char_Size(face, 0, size*64, 92, 92);
	
	maxAdvanceY = 0;
	
	// create bitmap for each letter and upload to opengl
	for (unsigned char i = 32; i < 128; i++) {
		
		Letter & letter = letters[i];
		
		FT_Load_Glyph(face, FT_Get_Char_Index(face, i), FT_LOAD_DEFAULT);
		
		FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
		FT_Bitmap & bitmap = face->glyph->bitmap;
		
		letter.w = next_p2(bitmap.width);
		letter.h = next_p2(bitmap.rows);
		letter.left = face->glyph->bitmap_left;
		letter.top = face->glyph->bitmap_top;
		letter.advancex = face->glyph->advance.x/64;
		// every glyph should have the same bounding box though,
		// so this would only need to be done once
		int thisCharHeight = ( face->bbox.yMax - face->bbox.yMin ) /64; 

		if ( thisCharHeight > maxAdvanceY ) {
			//~ cout << "(" << (char)i << ")" << (int)i << endl;
			maxAdvanceY = thisCharHeight;
			//~ cout << maxAdvanceY << endl;
		}
		
		// create the bitmap
		GLubyte *buffer, *cursor;
		GLubyte *src;
		
		buffer = new GLubyte[2 * letter.w * letter.h];
		cursor = buffer;
		src = bitmap.buffer;
		
		for (int y = 0; y < letter.h; y++) {
			for (int x = 0; x < letter.w; x++) {
				// fill 0 for padding
				if (x >= bitmap.width || y >= bitmap.rows) {
					*(cursor++) = 0;
					*(cursor++) = 0;
				} else {
					//write image
					*(cursor++) = *(src);
					*(cursor++) = *(src++);
				}
				
				
			}
		}
		
		// upload the buffer to opengl
		glGenTextures(1, &letter.tex);
		glBindTexture(GL_TEXTURE_2D, letter.tex);
		
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, letter.w, letter.h, 
			0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, buffer);
		
		
		delete [] buffer;
		
		
	} //~ end letter loop
	
	// close freetype
	FT_Done_Face(face);
	FT_Done_FreeType(library);
	maxAdvanceY = (int)(.8 * maxAdvanceY);
}



void Font::writeLetter(unsigned char ch, int x, int y) {
	if (ch > 128) return;
	Letter & letter = letters[ch];
	x += letter.left;
	y -= letter.top;
	
	// dumb
	glBindTexture(GL_TEXTURE_2D, letter.tex);
	
	glBegin(GL_QUADS);
	
	glTexCoord2f(0,0);
	glVertex3f(x, y, 0);
	
	glTexCoord2f(1,0);
	glVertex3f(x+letter.w, y, 0);
	
	glTexCoord2f(1,1);
	glVertex3f(x+letter.w, y+letter.h, 0);
	
	glTexCoord2f(0,1);
	glVertex3f(x, y+letter.h, 0);
	
	glEnd();
	
	
}

void Font::writeString(string s, int x, int y) {
	int cursor_x = x;
	int cursor_y = y;
	
	glEnable( GL_TEXTURE_2D );
	for (string::iterator i = s.begin(); i != s.end(); i++) {
		
		//~ if (*i == ' ') {
			//~ cursor_x+=letters['a'].advancex;
		//~ } else {
			writeLetter(*i, cursor_x, cursor_y);
			cursor_x+=letters[*i].advancex;
		//~ }
	}
	
}

int Font::widthOfString( string s ) {
	int width = 0;
	for ( int i = 0; i < s.length(); i ++ ) {
		width += letters[(int)s[i]].advancex;
	}
	return width;
}
